﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// В локальном режиме работы возвращает регламентные задания, соответствующие отбору.
// В модели сервиса - таблицу значений, в которой содержится описание найденных заданий
// в справочнике ОчередьЗаданий.
//
// Параметры:
//  Отбор - Структура - со свойствами: 
//          1) Общие для любого режима работы:
//             * УникальныйИдентификатор - УникальныйИдентификатор - идентификатор регламентного задания в локальном
//                                         режиме работы или идентификатор ссылки задания очереди в модели сервиса.
//                                       - Строка - строка уникального идентификатора регламентного задания в локальном
//                                         режиме работы или идентификатор ссылки задания очереди в модели сервиса.
//                                       - СправочникСсылка.ОчередьЗаданий - идентификатор задания
//                                            очереди в модели сервиса.
//                                       - СтрокаТаблицыЗначений из см. НайтиЗадания
//             * Метаданные              - ОбъектМетаданныхРегламентноеЗадание - метаданные регламентного задания.
//                                       - Строка - имя метаданных регламентного задания.
//             * Использование           - Булево - если Истина, задание включено.
//             * Ключ                    - Строка - прикладной идентификатор задания.
//          2) Возможные ключи только локального режима:
//             * Наименование            - Строка - наименование регламентного задания.
//             * Предопределенное        - Булево - если Истина, регламентное задание определено в метаданных.
//          3) Возможные ключи только для модели сервиса:
//             * ИмяМетода               - Строка - имя метода (или псевдоним) обработчика очереди задании.
//             * ОбластьДанных           - Число - значение разделителя области данных задания.
//             * СостояниеЗадания        - ПеречислениеСсылка.СостоянияЗаданий - состояние задания очереди.
//             * Шаблон                  - СправочникСсылка.ШаблоныЗаданийОчереди - шаблон задания, используется только
//                                            для разделенных заданий очереди.
//
// Возвращаемое значение:
//     Массив из РегламентноеЗадание - в локальном режиме работы массив регламентных заданий.
//     ТаблицаЗначений - в модели сервиса с колонками:
//        * Использование                - Булево - если Истина, задание включено.
//        * Ключ                         - Строка - прикладной идентификатор задания.
//        * Параметры                    - Массив - параметры, передаваемые в обработчик задания.
//        * Расписание                   - РасписаниеРегламентногоЗадания - расписание задания.
//        * УникальныйИдентификатор      - СправочникСсылка.ОчередьЗаданий - идентификатор задания
//                                            очереди в модели сервиса.
//        * ЗапланированныйМоментЗапуска - Дата - дата и время запланированного запуска задания
//                                         (в часовом поясе области данных).
//        * ИмяМетода                    - Строка - имя метода (или псевдоним) обработчика очереди задании.
//        * ОбластьДанных                - Число - значение разделителя области данных задания.
//        * СостояниеЗадания             - ПеречислениеСсылка.СостоянияЗаданий - состояние задания очереди.
//        * Шаблон                       - СправочникСсылка.ШаблоныЗаданийОчереди - шаблон задания,
//                                            используется только для разделенных заданий очереди.
//        * ЭксклюзивноеВыполнение       - Булево - при установленном флаге задание будет выполнено 
//                                                  даже при установленной блокировке начала сеансов в области
//                                                  данных. Так же если в области есть задания с таким флагом
//                                                  сначала будут выполнены они.
//        * ИнтервалПовтораПриАварийномЗавершении - Число - интервал в секундах, через который нужно перезапускать
//                                                          задание в случае его аварийного завершения.
//        * КоличествоПовторовПриАварийномЗавершении - Число - количество повторов при аварийном завершении задания.
//
Функция НайтиЗадания(Отбор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	КопияОтбора = ОбщегоНазначения.СкопироватьРекурсивно(Отбор); // см. НайтиЗадания.Отбор
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") Тогда
			
			Если КопияОтбора.Свойство("УникальныйИдентификатор") Тогда
				Если Не КопияОтбора.Свойство("Идентификатор") Тогда
					КопияОтбора.Вставить("Идентификатор", КопияОтбора.УникальныйИдентификатор);
				КонецЕсли;
				КопияОтбора.Удалить("УникальныйИдентификатор");
			КонецЕсли;
			
			Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
				// АПК:1386-выкл - модуль входит в подсистему ТехнологияСервиса.БазоваяФункциональность
				МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
				// АПК:1386-вкл.
				ОбластьДанных = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
				КопияОтбора.Вставить("ОбластьДанных", ОбластьДанных);
			КонецЕсли;
			
			МодульОчередьЗаданий  = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
			
			Если КопияОтбора.Свойство("Метаданные") Тогда
				Если ТипЗнч(КопияОтбора.Метаданные) = Тип("ОбъектМетаданных") Тогда
					МетаданныеРегламентноеЗадание = КопияОтбора.Метаданные;
				Иначе
					МетаданныеРегламентноеЗадание = Метаданные.РегламентныеЗадания.Найти(КопияОтбора.Метаданные);
				КонецЕсли;
				КопияОтбора.Удалить("Метаданные");
				КопияОтбора.Удалить("ИмяМетода");
				КопияОтбора.Удалить("Шаблон");
				Если МетаданныеРегламентноеЗадание <> Неопределено Тогда
					ШаблоныЗаданийОчереди = СтандартныеПодсистемыПовтИсп.ШаблоныЗаданийОчереди();
					Если ШаблоныЗаданийОчереди.Получить(МетаданныеРегламентноеЗадание.Имя) <> Неопределено Тогда
						УстановитьПривилегированныйРежим(Истина);
						Шаблон = МодульОчередьЗаданий.ШаблонПоИмени(МетаданныеРегламентноеЗадание.Имя);
						УстановитьПривилегированныйРежим(Ложь);
						КопияОтбора.Вставить("Шаблон", Шаблон);
					Иначе
						КопияОтбора.Вставить("ИмяМетода", МетаданныеРегламентноеЗадание.ИмяМетода);
					КонецЕсли;
				Иначе
					КопияОтбора.Вставить("ИмяМетода", Строка(Новый УникальныйИдентификатор));
				КонецЕсли;
			ИначеЕсли КопияОтбора.Свойство("Идентификатор") Тогда
				Если ТипЗнч(КопияОтбора.Идентификатор) = Тип("Строка") Тогда
					КопияОтбора.Идентификатор = Новый УникальныйИдентификатор(КопияОтбора.Идентификатор);
				КонецЕсли;
				Если ТипЗнч(КопияОтбора.Идентификатор) = Тип("УникальныйИдентификатор") Тогда
					КопияОтбора.Идентификатор = СсылкаЗаданияОчереди(КопияОтбора.Идентификатор, КопияОтбора);
				ИначеЕсли ТипЗнч(КопияОтбора.Идентификатор) = Тип("СтрокаТаблицыЗначений") Тогда
					КопияОтбора.Идентификатор = КопияОтбора.Идентификатор.Идентификатор;
				КонецЕсли;
			КонецЕсли;
			
			Возврат УточненныйСписокЗаданий(МодульОчередьЗаданий.ПолучитьЗадания(КопияОтбора));
			
		КонецЕсли;
	Иначе
		
		СписокЗаданий = РегламентныеЗадания.ПолучитьРегламентныеЗадания(КопияОтбора);
		
		Возврат СписокЗаданий;
		
	КонецЕсли;
	
КонецФункции

// Возвращает задание из очереди или регламентное.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                                     предопределенного регламентного задания.
//                - Строка - имя метаданных предопределенного регламентного задания в любом режиме работы
//                           или строка уникального идентификатора регламентного задания в локальном режиме работы
//                           или строка уникального идентификатора ссылки задания очереди в модели сервиса.
//                - УникальныйИдентификатор - идентификатор регламентного задания в локальном режиме работы
//                           или идентификатор ссылки задания очереди в модели сервиса.
//                - РегламентноеЗадание - регламентное задание из которого нужно получить уникальный идентификатор
//                           для получения свежей копии регламентного задания в локальном режиме работы.
//                - СправочникСсылка.ОчередьЗаданий - идентификатор задания очереди в модели сервиса.
//                - СтрокаТаблицыЗначений из см. НайтиЗадания
// 
// Возвращаемое значение:
//  РегламентноеЗадание - в локальном режиме работы.
//  СтрокаТаблицыЗначений из см. НайтиЗадания
//  Неопределено - задание не найдено.
//
Функция Задание(Знач Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Идентификатор = УточненныйИдентификаторЗадания(Идентификатор);
	РегламентноеЗадание = Неопределено;
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") Тогда
			Отбор = ?(ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных"),
				Новый Структура("Метаданные", Идентификатор),
				Новый Структура("УникальныйИдентификатор", Идентификатор));
			
			СписокЗаданий = НайтиЗадания(Отбор);
			Для Каждого Задание Из СписокЗаданий Цикл
				РегламентноеЗадание = Задание;
				Прервать;
			КонецЦикла;
		КонецЕсли;
		
	Иначе
		
		Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") Тогда
			Если Идентификатор.Предопределенное Тогда
				РегламентноеЗадание = РегламентныеЗадания.НайтиПредопределенное(Идентификатор);
			Иначе
				СписокЗаданий = РегламентныеЗадания.ПолучитьРегламентныеЗадания(Новый Структура("Метаданные", Идентификатор));
				Если СписокЗаданий.Количество() > 0 Тогда
					РегламентноеЗадание = СписокЗаданий[0];
				КонецЕсли;
			КонецЕсли; 
		Иначе
			РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
		КонецЕсли;
	КонецЕсли;
	
	Возврат РегламентноеЗадание;
	
КонецФункции

// Добавляет новое задание в очередь или регламентное.
// 
// Параметры: 
//  Параметры - Структура - параметры добавляемого задания, возможные свойства:
//   * Использование - Булево - Истина, если регламентное задание должно выполняться автоматически согласно расписанию. 
//   * Метаданные    - ОбъектМетаданныхРегламентноеЗадание - обязательно для указания. Объект метаданных, на основе 
//                              которого будет создано регламентное задание.
//   * Параметры     - Массив - параметры регламентного задания. Количество и состав параметров должны соответствовать 
//                              параметрам метода регламентного задания.
//   * Ключ          - Строка - прикладной идентификатор регламентного задания.
//   * ИнтервалПовтораПриАварийномЗавершении - Число - интервал в секундах, через который нужно перезапускать задание 
//                              в случае его аварийного завершения.
//   * Расписание    - РасписаниеРегламентногоЗадания - расписание задания.
//   * КоличествоПовторовПриАварийномЗавершении - Число - количество повторов при аварийном завершении задания.
//
// Возвращаемое значение:
//  РегламентноеЗадание - в локальном режиме работы.
//  СтрокаТаблицыЗначений из см. НайтиЗадания
// 
Функция ДобавитьЗадание(Параметры) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") Тогда
			
			ПараметрыЗадания = ОбщегоНазначения.СкопироватьРекурсивно(Параметры);
			
			Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
				// АПК:1386-выкл - модуль входит в подсистему ТехнологияСервиса.БазоваяФункциональность
				МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
				// АПК:1386-вкл.
				ОбластьДанных = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
				ПараметрыЗадания.Вставить("ОбластьДанных", ОбластьДанных);
			КонецЕсли;
			
			МетаданныеЗадания = ПараметрыЗадания.Метаданные;
			ИмяМетода = МетаданныеЗадания.ИмяМетода;
			ПараметрыЗадания.Вставить("ИмяМетода", ИмяМетода);
			
			ПараметрыЗадания.Удалить("Метаданные");
			ПараметрыЗадания.Удалить("Наименование");
			
			МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
			Задание = МодульОчередьЗаданий.ДобавитьЗадание(ПараметрыЗадания);
			Отбор = Новый Структура("Идентификатор", Задание);
			СписокЗаданий = УточненныйСписокЗаданий(МодульОчередьЗаданий.ПолучитьЗадания(Отбор));
			Для Каждого Задание Из СписокЗаданий Цикл
				Возврат Задание;
			КонецЦикла;
			
		КонецЕсли;
		
	Иначе
		Задание = ДобавитьРегламентноеЗадание(Параметры);
	КонецЕсли;
	
	Возврат Задание;
	
КонецФункции

// Удаляет задание из очереди или регламентное.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                                     непредопределенного регламентного задания.
//                - Строка - имя метаданных предопределенного регламентного задания в любом режиме работы
//                           или строка уникального идентификатора регламентного задания в локальном режиме работы
//                           или строка уникального идентификатора ссылки задания очереди в модели сервиса.
//                - УникальныйИдентификатор - идентификатор регламентного задания в локальном режиме работы.
//                           или идентификатор ссылки задания очереди в модели сервиса.
//                - РегламентноеЗадание - регламентное задание, уникальный идентификатор которого используется 
//                  для определения удаляемого экземпляра регламентного задания в локальном режиме работы.
//                - СправочникСсылка.ОчередьЗаданий - идентификатор задания очереди в модели сервиса.
//                - СтрокаТаблицыЗначений из см. НайтиЗадания
//
Процедура УдалитьЗадание(Знач Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Идентификатор = УточненныйИдентификаторЗадания(Идентификатор);
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") Тогда
			Если ТипЗнч(Идентификатор) = Тип("СтрокаТаблицыЗначений") Тогда
				СписокЗаданий = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Идентификатор);
			Иначе
				Отбор = ?(ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных"),
					Новый Структура("ИмяМетода", Идентификатор.ИмяМетода),
					Новый Структура("УникальныйИдентификатор", Идентификатор));
				СписокЗаданий = НайтиЗадания(Отбор);
			КонецЕсли;
			МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
			Для Каждого Задание Из СписокЗаданий Цикл
				МодульОчередьЗаданий.УдалитьЗадание(Задание.Идентификатор);
			КонецЦикла;
		КонецЕсли;
	Иначе
		УдалитьРегламентноеЗадание(Идентификатор);
	КонецЕсли;
	
КонецПроцедуры

// Изменяет задание очереди или регламентное.
//
// В модели сервиса (разделение включено):
// - в случае вызова в транзакции на задание устанавливается объектная блокировка,
// - если задание создано на основе шаблона или предопределенное, может быть указано
// только свойство Использование в параметре Параметры. Расписание в этом случае,
// изменять нельзя, т.к. оно хранится централизованно в неразделенном Шаблоне задания,
// отдельно для каждой области оно не сохраняется.
// 
// Параметры: 
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска.
//                - Строка - имя метаданных предопределенного регламентного задания в любом режиме работы
//                           или строка уникального идентификатора регламентного задания в локальном режиме работы
//                           или строка уникального идентификатора ссылки задания очереди в модели сервиса.
//                - УникальныйИдентификатор - идентификатор регламентного задания в локальном режиме работы
//                           или идентификатор ссылки задания очереди в модели сервиса.
//                - РегламентноеЗадание - регламентное задание в локальном режиме работы.
//                - СправочникСсылка.ОчередьЗаданий - идентификатор задания очереди в модели сервиса.
//                - СтрокаТаблицыЗначений из см. НайтиЗадания
//
//  Параметры - Структура - параметры, которые следует установить заданию, возможные свойства:
//   * Использование - Булево - Истина, если регламентное задание должно выполняться автоматически согласно расписанию.
//   * Параметры     - Массив - параметры регламентного задания. Количество и состав параметров должны соответствовать
//                              параметрам метода регламентного задания.
//   * Ключ          - Строка - прикладной идентификатор регламентного задания.
//   * ИнтервалПовтораПриАварийномЗавершении - Число - интервал в секундах, через который нужно перезапускать задание
//                              в случае его аварийного завершения.
//   * Расписание    - РасписаниеРегламентногоЗадания - расписание задания.
//   * КоличествоПовторовПриАварийномЗавершении - Число - количество повторов при аварийном завершении задания.
//   
Процедура ИзменитьЗадание(Знач Идентификатор, Знач Параметры) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Идентификатор = УточненныйИдентификаторЗадания(Идентификатор);
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") Тогда
			ПараметрыЗадания = ОбщегоНазначения.СкопироватьРекурсивно(Параметры);
			ПараметрыЗадания.Удалить("Наименование");
			Если ПараметрыЗадания.Количество() = 0 Тогда
				Возврат;
			КонецЕсли;
			
			Если ТипЗнч(Идентификатор) = Тип("СтрокаТаблицыЗначений") Тогда
				СписокЗаданий = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Идентификатор);
			Иначе
				Отбор = ?(ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных"),
					Новый Структура("Метаданные", Идентификатор),
					Новый Структура("УникальныйИдентификатор", Идентификатор));
				СписокЗаданий = НайтиЗадания(Отбор);
			КонецЕсли;
			
			// Если регламентное задание предопределенное и есть шаблон очереди,
			// тогда можно изменять только "Использование".
			ПараметрыПредопределенногоЗадания = Новый Структура;
			Если ПараметрыЗадания.Свойство("Использование") Тогда
				ПараметрыПредопределенногоЗадания.Вставить("Использование",
					ПараметрыЗадания.Использование);
			КонецЕсли;
			
			МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
			Для Каждого Задание Из СписокЗаданий Цикл
				Если Не ЗначениеЗаполнено(Задание.Шаблон) Тогда
					МодульОчередьЗаданий.ИзменитьЗадание(Задание.Идентификатор, ПараметрыЗадания);
				ИначеЕсли ЗначениеЗаполнено(ПараметрыПредопределенногоЗадания) Тогда
					МодульОчередьЗаданий.ИзменитьЗадание(Задание.Идентификатор, ПараметрыПредопределенногоЗадания);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
	Иначе
		ИзменитьРегламентноеЗадание(Идентификатор, Параметры);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает уникальный идентификатор задания из очереди или регламентного.
// Для вызова требуются права администрирования или УстановитьПривилегированныйРежим.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                                     регламентного задания.
//                - Строка - строка уникального идентификатора регламентного задания
//                           или идентификатора ссылки задания очереди в модели сервиса.
//                - УникальныйИдентификатор - идентификатор регламентного задания в локальном режиме работы
//                           или идентификатор ссылки задания очереди в модели сервиса.
//                - РегламентноеЗадание - регламентное задание.
//
// Возвращаемое значение:
//  УникальныйИдентификатор - идентификатор регламентного задания в локальном режиме работы
//                            или идентификатор ссылки задания очереди в модели сервиса.
// 
Функция УникальныйИдентификатор(Знач Идентификатор) Экспорт
	
	Возврат УникальныйИдентификаторЗадания(Идентификатор, Истина);
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции без поддержки заданий очереди в модели сервиса.

// Возвращает использование регламентного задания.
// Перед вызовом требуется иметь право администрирования или УстановитьПривилегированныйРежим.
//
// В модели сервиса работает с регламентными заданиями платформы, а не с заданиями очереди,
// одинаково как в разделенном, так и в неразделенном режимах.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                  предопределенного регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - Строка - строка уникального идентификатора регламентного задания.
//                - РегламентноеЗадание - регламентное задание.
//
// Возвращаемое значение:
//  Булево - Истина, если регламентное задание используется.
// 
Функция РегламентноеЗаданиеИспользуется(Знач Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Задание = ПолучитьРегламентноеЗадание(Идентификатор);
	
	Возврат Задание.Использование;
	
КонецФункции

// Возвращает расписание регламентного задания.
// Перед вызовом требуется иметь право администрирования или УстановитьПривилегированныйРежим.
//
// В модели сервиса работает с регламентными заданиями платформы, а не с заданиями очереди,
// одинаково как в разделенном, так и в неразделенном режимах.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                  предопределенного регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - Строка - строка уникального идентификатора регламентного задания.
//                - РегламентноеЗадание - регламентное задание.
//
//  ВСтруктуре    - Булево - если Истина, тогда расписание будет преобразовано
//                  в структуру, которую можно передать на клиент.
// 
// Возвращаемое значение:
//  РасписаниеРегламентногоЗадания, Структура - структура содержит те же свойства, что и расписание.
// 
Функция РасписаниеРегламентногоЗадания(Знач Идентификатор, Знач ВСтруктуре = Ложь) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Задание = ПолучитьРегламентноеЗадание(Идентификатор);
	
	Если ВСтруктуре Тогда
		Возврат ОбщегоНазначенияКлиентСервер.РасписаниеВСтруктуру(Задание.Расписание);
	КонецЕсли;
	
	Возврат Задание.Расписание;
	
КонецФункции

// Устанавливает использование регламентного задания.
// Перед вызовом требуется иметь право администрирования или УстановитьПривилегированныйРежим.
//
// В модели сервиса работает с регламентными заданиями платформы, а не с заданиями очереди,
// одинаково как в разделенном, так и в неразделенном режимах.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных        - объект метаданных регламентного задания для поиска
//                                            предопределенного регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - Строка                  - строка уникального идентификатора регламентного задания.
//                - РегламентноеЗадание     - регламентное задание.
//  Использование - Булево                  - значение использования которое нужно установить.
//
Процедура УстановитьИспользованиеРегламентногоЗадания(Знач Идентификатор, Знач Использование) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	ИдентификаторЗадания = УникальныйИдентификаторЗадания(Идентификатор);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
	ЭлементБлокировки.УстановитьЗначение("Идентификатор", Строка(ИдентификаторЗадания));
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Задание = ПолучитьРегламентноеЗадание(ИдентификаторЗадания);
		
		Если Задание.Использование <> Использование Тогда
			Задание.Использование = Использование;
			Задание.Записать();
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Устанавливает расписание регламентного задания.
// Перед вызовом требуется иметь право администрирования или УстановитьПривилегированныйРежим.
//
// В модели сервиса работает с регламентными заданиями платформы, а не с заданиями очереди,
// одинаково как в разделенном, так и в неразделенном режимах.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                  предопределенного регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - Строка - строка уникального идентификатора регламентного задания.
//                - РегламентноеЗадание - регламентное задание.
//
//  Расписание    - РасписаниеРегламентногоЗадания - расписание.
//                - Структура - значение возвращаемое функцией РасписаниеВСтруктуру
//                  общего модуля ОбщегоНазначенияКлиентСервер.
// 
Процедура УстановитьРасписаниеРегламентногоЗадания(Знач Идентификатор, Знач Расписание) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	ИдентификаторЗадания = УникальныйИдентификаторЗадания(Идентификатор);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
	ЭлементБлокировки.УстановитьЗначение("Идентификатор", Строка(ИдентификаторЗадания));
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Задание = ПолучитьРегламентноеЗадание(ИдентификаторЗадания);
		
		Если ТипЗнч(Расписание) = Тип("РасписаниеРегламентногоЗадания") Тогда
			Задание.Расписание = Расписание;
		Иначе
			Задание.Расписание = ОбщегоНазначенияКлиентСервер.СтруктураВРасписание(Расписание);
		КонецЕсли;
		
		Задание.Записать();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Возвращает РегламентноеЗадание из информационной базы.
//
// В модели сервиса работает с регламентными заданиями платформы, а не с заданиями очереди,
// одинаково как в разделенном, так и в неразделенном режимах.
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                  предопределенного регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - Строка - строка уникального идентификатора регламентного задания.
//                - РегламентноеЗадание - регламентное задание из которого нужно получить
//                  уникальный идентификатор для получения свежей копии регламентного задания.
// 
// Возвращаемое значение:
//  РегламентноеЗадание - прочитано из базы данных.
//
Функция ПолучитьРегламентноеЗадание(Знач Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Если ТипЗнч(Идентификатор) = Тип("РегламентноеЗадание") Тогда
		Идентификатор = Идентификатор.УникальныйИдентификатор;
	КонецЕсли;
	
	Если ТипЗнч(Идентификатор) = Тип("Строка") Тогда
		Идентификатор = Новый УникальныйИдентификатор(Идентификатор);
	КонецЕсли;
	
	Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") Тогда
		РегламентноеЗадание = РегламентныеЗадания.НайтиПредопределенное(Идентификатор);
	Иначе
		РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
	КонецЕсли;
	
	Если РегламентноеЗадание = Неопределено Тогда
		ВызватьИсключение( НСтр("ru = 'Регламентное задание не существует.
		                              |Возможно оно удалено другим пользователем.'") );
	КонецЕсли;
	
	Возврат РегламентноеЗадание;
	
КонецФункции

// Возвращает результаты последнего запуска указанного регламентного задания.
// В том числе, если оно было запущено вручную из обработки "Регламентные и фоновые задания".
// 
// Параметры:
//  Задание - РегламентноеЗадание - для указанного регламентного задания будут получены
//                                  результаты последнего запуска.
//          - Строка - уникальный идентификатор регламентного задания
//
// Возвращаемое значение:
//  Неопределено
//  Структура:
//     * Идентификатор - Строка
//     * Наименование - Строка
//     * Ключ - Строка
//     * Конец - Дата
//     * ИдентификаторРегламентногоЗадания - Строка
//     * Состояние - СостояниеФоновогоЗадания
//     * ИмяМетода - Строка
//     * Расположение - Строка
//     * ОписаниеИнформацииОбОшибке - Строка
//     * ПопыткаЗапуска - Число
//     * СообщенияПользователю - Массив
//     * НомерСеанса - Число
//     * НачалоСеанса - Дата
//
Функция СвойстваПоследнегоЗадания(Знач Задание) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	Если ТипЗнч(Задание) = Тип("РегламентноеЗадание") Тогда
		Задание = Задание.УникальныйИдентификатор;
	КонецЕсли;
	
	Если ТипЗнч(Задание) = Тип("Строка") Тогда
		Задание = Новый УникальныйИдентификатор(Задание);
	КонецЕсли;
	
	РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Задание);
	ТекущийОтбор = Новый Структура("ИмяМетода", РегламентноеЗадание.Метаданные.ИмяМетода);
	Результат = ФоновыеЗадания.ПолучитьФоновыеЗадания(ТекущийОтбор);
	Если Результат.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ПоследнееФоновое = ПоследнееФоновоеЗаданиеВМассиве(Результат);
	
	СвойстваФоновогоЗадания = НовыеСвойстваФоновыхЗаданий();
	ЗаполнитьЗначенияСвойств(СвойстваФоновогоЗадания, ПоследнееФоновое);
	
	СвойстваФоновогоЗадания.Идентификатор = ПоследнееФоновое.УникальныйИдентификатор;
	СвойстваФоновогоЗадания.ИдентификаторРегламентногоЗадания = Задание;
	Возврат СвойстваФоновогоЗадания;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Прочие процедуры и функции.

// Возвращает признак установленной блокировки работы с внешними ресурсами.
//
// Возвращаемое значение:
//   Булево   - Истина, если работа с внешними ресурсами заблокирована.
//
Функция РаботаСВнешнимиРесурсамиЗаблокирована() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
		МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщегоНазначения.ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
		Возврат МодульБлокировкаРаботыСВнешнимиРесурсами.РаботаСВнешнимиРесурсамиЗаблокирована();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Разрешает работу с внешними ресурсами.
//
Процедура РазблокироватьРаботуСВнешнимиРесурсами() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
		МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщегоНазначения.ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
		МодульБлокировкаРаботыСВнешнимиРесурсами.РазрешитьРаботуСВнешнимиРесурсами();
	КонецЕсли;
	
КонецПроцедуры

// Запрещает работу с внешними ресурсами.
//
Процедура ЗаблокироватьРаботуСВнешнимиРесурсами() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
		МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщегоНазначения.ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
		МодульБлокировкаРаботыСВнешнимиРесурсами.ЗапретитьРаботуСВнешнимиРесурсами();
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Устанавливает требуемые значения параметров регламентного задания.
// В модели сервиса для задания, созданного на основе шаблона очереди заданий,
// может быть изменено только значение свойства Использование.
//
// Параметры:
//  РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - задание, свойства которого
//                        требуется изменить.
//  ИзменяемыеПараметры - Структура - свойства регламентного задания, которые требуется изменить.
//                        Ключ структуры - имя параметра, а значение - значение параметра формы.
//  Отбор               - см. НайтиЗадания.Отбор.
//
Процедура УстановитьПараметрыРегламентногоЗадания(РегламентноеЗадание, ИзменяемыеПараметры, Отбор = Неопределено) Экспорт
	
	Если Отбор = Неопределено Тогда
		Отбор = Новый Структура;
	КонецЕсли;
	Отбор.Вставить("Метаданные", РегламентноеЗадание);
	
	СписокЗаданий = НайтиЗадания(Отбор);
	Если СписокЗаданий.Количество() = 0 Тогда
		ИзменяемыеПараметры.Вставить("Метаданные", РегламентноеЗадание);
		ДобавитьЗадание(ИзменяемыеПараметры);
	Иначе
		Для Каждого Задание Из СписокЗаданий Цикл
			ИзменитьЗадание(Задание, ИзменяемыеПараметры);
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

// Устанавливает использование предопределенного регламентного задания.
//
// Параметры:
//  ЗаданиеМетаданные - ОбъектМетаданных - метаданные предопределенного регламентного задания.
//  Использование     - Булево - Истина, если задание нужно включить, иначе Ложь.
//
Процедура УстановитьИспользованиеПредопределенногоРегламентногоЗадания(ЗаданиеМетаданные, Использование) Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Отбор     = Новый Структура;
		Отбор.Вставить("Метаданные", ЗаданиеМетаданные);
		Параметры = Новый Структура;
		Параметры.Вставить("Использование", Использование);
		Задания = НайтиЗадания(Отбор);
		Для Каждого Задание Из Задания Цикл
			ИзменитьЗадание(Задание, Параметры);
			Прервать;
		КонецЦикла;
	Иначе
		ИдентификаторЗадания = УникальныйИдентификаторЗадания(ЗаданиеМетаданные);
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
		ЭлементБлокировки.УстановитьЗначение("Идентификатор", Строка(ИдентификаторЗадания));
		
		НачатьТранзакцию();
		Попытка
			Блокировка.Заблокировать();
			Задание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
			
			Если Задание.Использование <> Использование Тогда
				Задание.Использование = Использование;
				Задание.Записать();
			КонецЕсли;
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЕсли;
	
КонецПроцедуры

// Отменяет выполнение фоновых заданий для регламентного задания
// и делает запись в журнал регистрации.
//
Процедура ОтменитьВыполнениеЗадания(Знач РегламентноеЗадание, ТекстДляЖурнала) Экспорт
	
	ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
	Если ТекущийСеанс = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если РегламентноеЗадание = Неопределено Тогда
		Для Каждого Задание Из Метаданные.РегламентныеЗадания Цикл
			Если Задание.ИмяМетода = ТекущийСеанс.ИмяМетода Тогда
				РегламентноеЗадание = Задание;
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Если РегламентноеЗадание = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяСобытия = НСтр("ru = 'Отмена фонового задания'", ОбщегоНазначения.КодОсновногоЯзыка());
	
	ЗаписьЖурналаРегистрации(ИмяСобытия,
		УровеньЖурналаРегистрации.Предупреждение,
		РегламентноеЗадание,
		,
		ТекстДляЖурнала);
	
	ТекущийСеанс.Отменить();
	ТекущийСеанс.ОжидатьЗавершенияВыполнения(1);
	
КонецПроцедуры

Функция ПараметрРегламентногоЗадания(РегламентноеЗадание, ИмяСвойства, ЗначениеПоУмолчанию) Экспорт
	
	ПараметрыЗадания = Новый Структура;
	ПараметрыЗадания.Вставить("Метаданные", РегламентноеЗадание);
	
	УстановитьПривилегированныйРежим(Истина);
	
	СписокЗаданий = НайтиЗадания(ПараметрыЗадания);
	Для Каждого Задание Из СписокЗаданий Цикл
		Возврат Задание[ИмяСвойства];
	КонецЦикла;
	
	Возврат ЗначениеПоУмолчанию;
	
КонецФункции

// Устанавливает исключительную управляемую блокировку для записи регламентных заданий.
//  Технически, блокировка устанавливается на регистр сведений КэшПрограммныхИнтерфейсов.
//
// Параметры:
//  Идентификатор - УникальныйИдентификатор - идентификатор регламентного задания.
//                - ОбъектМетаданныхРегламентноеЗадание - перед добавления нового без дублей.
//
Процедура ЗаблокироватьРегламентноеЗадание(Идентификатор) Экспорт 
	
	Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") Тогда
		ИдентификаторБлокировки = Идентификатор.Имя;
	Иначе
		ИдентификаторБлокировки = Строка(Идентификатор);
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
	ЭлементБлокировки.УстановитьЗначение("Идентификатор", ИдентификаторБлокировки);
	Блокировка.Заблокировать();
	
КонецПроцедуры

// Добавляет новое регламентное задание (без учета очереди заданий модели сервиса).
// 
// Параметры: 
//  Параметры - Структура - параметры добавляемого задания, возможные свойства:
//   * Использование - Булево - Истина, если регламентное задание должно выполняться автоматически согласно расписанию. 
//   * Метаданные    - ОбъектМетаданныхРегламентноеЗадание - обязательно для указания. Объект метаданных, на основе 
//                              которого будет создано регламентное задание.
//   * Параметры     - Массив - параметры регламентного задания. Количество и состав параметров должны соответствовать 
//                              параметрам метода регламентного задания.
//   * Ключ          - Строка - прикладной идентификатор регламентного задания.
//   * ИнтервалПовтораПриАварийномЗавершении - Число - интервал в секундах, через который нужно перезапускать задание 
//                              в случае его аварийного завершения.
//   * Расписание    - РасписаниеРегламентногоЗадания - расписание задания.
//   * КоличествоПовторовПриАварийномЗавершении - Число - количество повторов при аварийном завершении задания.
//
// Возвращаемое значение:
//  РегламентноеЗадание
//
Функция ДобавитьРегламентноеЗадание(Параметры) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	МетаданныеЗадания = Параметры.Метаданные;
	Задание = РегламентныеЗадания.СоздатьРегламентноеЗадание(МетаданныеЗадания);
	
	Если Параметры.Свойство("Наименование") Тогда
		Задание.Наименование = Параметры.Наименование;
	Иначе
		Задание.Наименование = МетаданныеЗадания.Наименование;
	КонецЕсли;
	
	Если Параметры.Свойство("Использование") Тогда
		Задание.Использование = Параметры.Использование;
	Иначе
		Задание.Использование = МетаданныеЗадания.Использование;
	КонецЕсли;
	
	Если Параметры.Свойство("Ключ") Тогда
		Задание.Ключ = Параметры.Ключ;
	Иначе
		Задание.Ключ = МетаданныеЗадания.Ключ;
	КонецЕсли;
	
	Если Параметры.Свойство("ИмяПользователя") Тогда
		Задание.ИмяПользователя = Параметры.ИмяПользователя;
	КонецЕсли;
	
	Если Параметры.Свойство("ИнтервалПовтораПриАварийномЗавершении") Тогда
		Задание.ИнтервалПовтораПриАварийномЗавершении = Параметры.ИнтервалПовтораПриАварийномЗавершении;
	Иначе
		Задание.ИнтервалПовтораПриАварийномЗавершении = МетаданныеЗадания.ИнтервалПовтораПриАварийномЗавершении;
	КонецЕсли;
	
	Если Параметры.Свойство("КоличествоПовторовПриАварийномЗавершении") Тогда
		Задание.КоличествоПовторовПриАварийномЗавершении = Параметры.КоличествоПовторовПриАварийномЗавершении;
	Иначе
		Задание.КоличествоПовторовПриАварийномЗавершении = МетаданныеЗадания.КоличествоПовторовПриАварийномЗавершении;
	КонецЕсли;
	
	Если Параметры.Свойство("Параметры") Тогда
		Задание.Параметры = Параметры.Параметры;
	КонецЕсли;
	
	Если Параметры.Свойство("Расписание") Тогда
		Задание.Расписание = Параметры.Расписание;
	КонецЕсли;
	
	Задание.Записать();
	
	Возврат Задание;
	
КонецФункции

// Удаляет непредопределенное регламентное задание (без учета очереди заданий модели сервиса).
//
// Параметры:
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                                     непредопределенного регламентного задания.
//                - Строка - имя метаданных предопределенного регламентного задания
//                           или строка уникального идентификатора регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - РегламентноеЗадание - регламентное задание, уникальный идентификатор которого используется 
//                  для определения удаляемого экземпляра регламентного задания.
//
Процедура УдалитьРегламентноеЗадание(Знач Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Идентификатор = УточненныйИдентификаторЗадания(Идентификатор);
	
	СписокЗаданий = Новый Массив; // Массив из РегламентноеЗадание.
	
	Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") Тогда
		Отбор = Новый Структура("Метаданные, Предопределенное", Идентификатор, Ложь);
		СписокЗаданий = РегламентныеЗадания.ПолучитьРегламентныеЗадания(Отбор);
	Иначе
		РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
		Если РегламентноеЗадание <> Неопределено Тогда
			СписокЗаданий.Добавить(РегламентноеЗадание);
		КонецЕсли;
	КонецЕсли;
	
	Для Каждого РегламентноеЗадание Из СписокЗаданий Цикл
		ИдентификаторЗадания = УникальныйИдентификаторЗадания(РегламентноеЗадание);
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
		ЭлементБлокировки.УстановитьЗначение("Идентификатор", Строка(ИдентификаторЗадания));
		
		НачатьТранзакцию();
		Попытка
			Блокировка.Заблокировать();
			Задание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
			Если Задание <> Неопределено Тогда
				Задание.Удалить();
			КонецЕсли;
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЦикла;
	
КонецПроцедуры

// Изменяет регламентное задание (без учета очереди заданий модели сервиса).
//
// Параметры: 
//  Идентификатор - ОбъектМетаданных - объект метаданных регламентного задания для поиска
//                                     непредопределенного регламентного задания.
//                - Строка - имя метаданных предопределенного регламентного задания
//                           или строка уникального идентификатора регламентного задания.
//                - УникальныйИдентификатор - идентификатор регламентного задания.
//                - РегламентноеЗадание - регламентное задание.
//
//  Параметры - Структура - параметры, которые следует установить заданию, возможные свойства:
//   * Использование - Булево - Истина, если регламентное задание должно выполняться автоматически согласно расписанию.
//   * Параметры     - Массив - параметры регламентного задания. Количество и состав параметров должны соответствовать
//                              параметрам метода регламентного задания.
//   * Ключ          - Строка - прикладной идентификатор регламентного задания.
//   * ИнтервалПовтораПриАварийномЗавершении - Число - интервал в секундах, через который нужно перезапускать задание
//                              в случае его аварийного завершения.
//   * Расписание    - РасписаниеРегламентногоЗадания - расписание задания.
//   * КоличествоПовторовПриАварийномЗавершении - Число - количество повторов при аварийном завершении задания.
//   
Процедура ИзменитьРегламентноеЗадание(Знач Идентификатор, Знач Параметры) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	
	Идентификатор = УточненныйИдентификаторЗадания(Идентификатор);
	ИдентификаторЗадания = УникальныйИдентификаторЗадания(Идентификатор);
	
	Если ИдентификаторЗадания = Неопределено Тогда
		ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Регламентное задание по переданному идентификатору не найдено.
				|
				|Если регламентное задание не предопределенное, то его необходимо сначала добавить
				|в список заданий при помощи метода %1.'"),
			"РегламентныеЗаданияСервер.ДобавитьЗадание");
		
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
	ЭлементБлокировки.УстановитьЗначение("Идентификатор", Строка(ИдентификаторЗадания));
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Задание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
		Если Задание <> Неопределено Тогда
			ЕстьИзменения = Ложь;
			
			ОбновитьЗначениеСвойстваЗадания(Задание, "Наименование", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "Использование", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "Ключ", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "ИмяПользователя", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "ИнтервалПовтораПриАварийномЗавершении", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "КоличествоПовторовПриАварийномЗавершении", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "Параметры", Параметры, ЕстьИзменения);
			ОбновитьЗначениеСвойстваЗадания(Задание, "Расписание", Параметры, ЕстьИзменения);
			
			Если ЕстьИзменения Тогда
				Задание.Записать();
			КонецЕсли;
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Параметры:
//   МассивФоновыхЗаданий - Массив из ФоновоеЗадание
//   ПоследнееФоновоеЗадание - ФоновоеЗадание
//                           - Неопределено
// Возвращаемое значение:
//   ФоновоеЗадание, Неопределено
//
Функция ПоследнееФоновоеЗаданиеВМассиве(МассивФоновыхЗаданий, ПоследнееФоновоеЗадание = Неопределено) Экспорт
	
	Для каждого ТекущееФоновоеЗадание Из МассивФоновыхЗаданий Цикл
		Если ПоследнееФоновоеЗадание = Неопределено Тогда
			ПоследнееФоновоеЗадание = ТекущееФоновоеЗадание;
			Продолжить;
		КонецЕсли;
		Если ЗначениеЗаполнено(ПоследнееФоновоеЗадание.Конец) Тогда
			Если НЕ ЗначениеЗаполнено(ТекущееФоновоеЗадание.Конец)
			 ИЛИ ПоследнееФоновоеЗадание.Конец < ТекущееФоновоеЗадание.Конец Тогда
				ПоследнееФоновоеЗадание = ТекущееФоновоеЗадание;
			КонецЕсли;
		Иначе
			Если НЕ ЗначениеЗаполнено(ТекущееФоновоеЗадание.Конец)
			   И ПоследнееФоновоеЗадание.Начало < ТекущееФоновоеЗадание.Начало Тогда
				ПоследнееФоновоеЗадание = ТекущееФоновоеЗадание;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ПоследнееФоновоеЗадание;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция УточненныйИдентификаторЗадания(Знач Идентификатор)
	
	Если ТипЗнч(Идентификатор) = Тип("РегламентноеЗадание") Тогда
		Идентификатор = Идентификатор.УникальныйИдентификатор;
	КонецЕсли;
	
	Если ТипЗнч(Идентификатор) = Тип("Строка") Тогда
		ОбъектМетаданных = Метаданные.РегламентныеЗадания.Найти(Идентификатор);
		Если ОбъектМетаданных = Неопределено Тогда
			Идентификатор = Новый УникальныйИдентификатор(Идентификатор);
		Иначе
			Идентификатор = ОбъектМетаданных;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Идентификатор;
	
КонецФункции

Функция УникальныйИдентификаторЗадания(Знач Идентификатор, ВРазделенномРежимеИдентификаторЗаданияОчереди = Ложь)
	
	Если ТипЗнч(Идентификатор) = Тип("УникальныйИдентификатор") Тогда
		Возврат Идентификатор;
	КонецЕсли;
	
	Если ТипЗнч(Идентификатор) = Тип("РегламентноеЗадание") Тогда
		Возврат Идентификатор.УникальныйИдентификатор;
	КонецЕсли;
	
	Если ТипЗнч(Идентификатор) = Тип("Строка") Тогда
		Возврат Новый УникальныйИдентификатор(Идентификатор);
	КонецЕсли;
	
	Если ВРазделенномРежимеИдентификаторЗаданияОчереди
	   И ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") Тогда
			ПараметрыЗадания = Новый Структура("Метаданные", Идентификатор);
			СписокЗаданий = НайтиЗадания(ПараметрыЗадания);
			Если СписокЗаданий = Неопределено Тогда
				Возврат Неопределено;
			КонецЕсли;
			
			Для Каждого Задание Из СписокЗаданий Цикл
				Возврат Задание.Идентификатор.УникальныйИдентификатор();
			КонецЦикла;
		ИначеЕсли ТипЗнч(Идентификатор) = Тип("СтрокаТаблицыЗначений") Тогда
			Возврат Идентификатор.Идентификатор.УникальныйИдентификатор();
		ИначеЕсли ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Идентификатор)) Тогда
			Возврат Идентификатор.УникальныйИдентификатор();
		Иначе
			Возврат Неопределено;
		КонецЕсли;
	Иначе
		Если ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") И Идентификатор.Предопределенное Тогда
			Возврат РегламентныеЗадания.НайтиПредопределенное(Идентификатор).УникальныйИдентификатор;
		ИначеЕсли ТипЗнч(Идентификатор) = Тип("ОбъектМетаданных") И НЕ Идентификатор.Предопределенное Тогда
			СписокЗаданий = РегламентныеЗадания.ПолучитьРегламентныеЗадания(Новый Структура("Метаданные", Идентификатор));
			Для каждого РегламентноеЗадание Из СписокЗаданий Цикл
				Возврат РегламентноеЗадание.УникальныйИдентификатор;
			КонецЦикла; 
		КонецЕсли;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Для процедуры ИзменитьЗадание.
Процедура ОбновитьЗначениеСвойстваЗадания(Задание, ИмяСвойства, ПараметрыЗадания, ЕстьИзменения)
	
	Если Не ПараметрыЗадания.Свойство(ИмяСвойства) Тогда
		Возврат;
	КонецЕсли;
	
	Если Задание[ИмяСвойства] = ПараметрыЗадания[ИмяСвойства]
	 Или ТипЗнч(Задание[ИмяСвойства]) = Тип("РасписаниеРегламентногоЗадания")
	   И ТипЗнч(ПараметрыЗадания[ИмяСвойства]) = Тип("РасписаниеРегламентногоЗадания")
	   И Строка(Задание[ИмяСвойства]) = Строка(ПараметрыЗадания[ИмяСвойства]) Тогда
		
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Задание[ИмяСвойства]) = Тип("РасписаниеРегламентногоЗадания") 
		И ТипЗнч(ПараметрыЗадания[ИмяСвойства]) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Задание[ИмяСвойства], ПараметрыЗадания[ИмяСвойства]);
	Иначе
		Задание[ИмяСвойства] = ПараметрыЗадания[ИмяСвойства];
	КонецЕсли;
	
	ЕстьИзменения = Истина;
	
КонецПроцедуры

// Для функций НайтиЗадания, Задание, ДобавитьЗадание.
Функция УточненныйСписокЗаданий(СписокЗаданий)
	
	// Для обратной совместимости поле Идентификатор не удаляется.
	КопияСписка = СписокЗаданий.Скопировать();
	КопияСписка.Колонки.Добавить("УникальныйИдентификатор");
	Для Каждого Строка Из КопияСписка Цикл
		Строка.УникальныйИдентификатор = Строка.Идентификатор;
	КонецЦикла;
	
	Возврат КопияСписка;
	
КонецФункции

// Для функций НайтиЗадание, Задание, УдалитьЗадание, ИзменитьЗадание.
Функция СсылкаЗаданияОчереди(Идентификатор, ПараметрыЗадания)
	
	МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
	СправочникДляЗадания = МодульОчередьЗаданий.СправочникОчередьЗаданий();
	
	Возврат СправочникДляЗадания.ПолучитьСсылку(Идентификатор);
	
КонецФункции

// Вызывает исключение, если у пользователя нет права администрирования.
Процедура ВызватьИсключениеЕслиНетПраваАдминистрирования()
	
	ПроверятьПраваАдминистрированияСистемы = Истина;
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		ПроверятьПраваАдминистрированияСистемы = Ложь;
	КонецЕсли;
	
	Если НЕ Пользователи.ЭтоПолноправныйПользователь(, ПроверятьПраваАдминистрированияСистемы) Тогда
		ВызватьИсключение НСтр("ru = 'Нарушение прав доступа.'");
	КонецЕсли;
	
КонецПроцедуры

Функция НовыеСвойстваФоновыхЗаданий()
	
	СвойстваФоновыхЗаданий = Новый Структура;
	СвойстваФоновыхЗаданий.Вставить("Идентификатор");
	СвойстваФоновыхЗаданий.Вставить("Ключ");
	СвойстваФоновыхЗаданий.Вставить("Начало");
	СвойстваФоновыхЗаданий.Вставить("Конец");
	СвойстваФоновыхЗаданий.Вставить("ИдентификаторРегламентногоЗадания");
	СвойстваФоновыхЗаданий.Вставить("Состояние");
	СвойстваФоновыхЗаданий.Вставить("ИмяМетода");
	СвойстваФоновыхЗаданий.Вставить("Расположение");
	СвойстваФоновыхЗаданий.Вставить("ПопыткаЗапуска");
	СвойстваФоновыхЗаданий.Вставить("СообщенияПользователю");
	СвойстваФоновыхЗаданий.Вставить("НомерСеанса");
	СвойстваФоновыхЗаданий.Вставить("НачалоСеанса");
	
	Возврат СвойстваФоновыхЗаданий;
	
КонецФункции

#КонецОбласти